#include "imageviewer.h"

#include <QMessageBox>
#include <exception>
#include <stdexcept>

/// Parameter: f: zoom factor
/// Return:
/// Action: Zooms to the image based on the given factor and sets the scrollbars.
void ImageViewer::zoom(const double f)
{
    QScrollBar* scrollbarHor = _scrollArea->horizontalScrollBar();
    QScrollBar* scrollbarVer = _scrollArea->verticalScrollBar();

    _label->resize(_factor * _label->pixmap()->size());

    scrollbarHor->setValue(int(f * scrollbarHor->value() + ((f - 1) * scrollbarHor->pageStep() / 2)));
    scrollbarVer->setValue(int(f * scrollbarVer->value() + ((f - 1) * scrollbarVer->pageStep() / 2)));

    scrollbarHor->setEnabled(true);
    scrollbarVer->setEnabled(true);
}

/// Parameter:
/// Return:
/// Action: Zoom in.
void ImageViewer::zoom_in()
{
    if (_factor > 5)
        return;

    _factor *= 1.25;
    double f = 1.25;
    zoom(f);
}

/// Parameter:
/// Return:
/// Action: Zoom out.
void ImageViewer::zoom_out()
{
    if (_factor < 0.2)
        return;

    _factor *= 0.8;
    double f = 0.8;
    zoom(f);
}

/// Parameter:
/// Return:
/// Action: Signals that the vertical scrollbar has been moved.
///         It is for the synchronization of the images.
void ImageViewer::ver_moved_slot(int value)
{
    emit ver_moved(value);
}

/// Parameter:
/// Return:
/// Action: Signals that the horizontal scrollbar has been moved.
///         It is for the synchronization of the images.
void ImageViewer::hor_moved_slot(int value)
{
    emit hor_moved(value);
}

/// Parameter: img: Image to be showed
///            parent: parent Widget
/// Return:
/// Action: Constructor
///         Sets the properties and constructs the widget
ImageViewer::ImageViewer(QImage* img, QWidget *parent) :
    QWidget(parent)
{
    _image = new QImage;
    *_image = img->copy();

    if (_image->isNull())
    {
        std::runtime_error ex("Image is too large");
        throw ex;
    }

    _label = new QLabel;
    _label->setPixmap(QPixmap::fromImage(*_image));
    _label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
    _label->setScaledContents(true);

    _layout = new QHBoxLayout;
    _scrollArea = new QScrollArea;
    _scrollArea->setWidget(_label);

    connect(_scrollArea->verticalScrollBar(), SIGNAL(sliderMoved(int)), this, SLOT(ver_moved_slot(int)));
    connect(_scrollArea->horizontalScrollBar(), SIGNAL(sliderMoved(int)), this, SLOT(hor_moved_slot(int)));

    _layout->addWidget(_scrollArea);
    setLayout(_layout);

    _factor = 1.0;
}

/// Parameter:
/// Return:
/// Action: Destructor
ImageViewer::~ImageViewer()
{
    delete _layout;
}

/// Parameter: e: wheel event caused by scrolling
/// Return:
/// Action: Calculates the factor for zooming and zooms
void ImageViewer::wheelEvent(QWheelEvent *e)
{
    QScrollBar* scrollbarHor = _scrollArea->horizontalScrollBar();
    QScrollBar* scrollbarVer = _scrollArea->verticalScrollBar();

    scrollbarHor->setEnabled(true);
    scrollbarVer->setEnabled(true);

    QPoint degree = e->angleDelta() / 8;

    double f;
    if (degree.y() < 0)
    {
        if (_factor < 0.2)
            return;

        _factor *= 0.8;
        f = 0.8;
    }
    else
    {
        if (_factor > 5)
            return;

        _factor *= 1.25;
        f = 1.25;
    }

    zoom(f);

    e->accept();
}

/// Parameter: value: vertical scrollbar's position
/// Return:
/// Action: Sets the vertical scrollbar's position
void ImageViewer::move_vertical_scrollbar(const int value)
{
    if (_scrollArea->verticalScrollBar()->value() != value)
        _scrollArea->verticalScrollBar()->setValue(value);
}

/// Parameter: value: horizontal scrollbar's position
/// Return:
/// Action: Sets the horizontal scrollbar's position
void ImageViewer::move_horizontal_scrollbar(const int value)
{
    if (_scrollArea->horizontalScrollBar()->value() != value)
        _scrollArea->horizontalScrollBar()->setValue(value);
}

/// Parameter:
/// Return:
/// Action: Sets the scroll area to the start point.
void ImageViewer::zoom_reset()
{
    _label->adjustSize();
    _factor = 1.0;
}

/// Parameter: img: Image to be showed.
/// Return:
/// Action: Changes the currently showed image to the parameter image.
void ImageViewer::change_image(QImage* img)
{
    if (img->isNull())
        return;

    *_image = img->copy();

    if (_image->isNull())
    {
        std::runtime_error ex("Error during changing images");
        throw ex;
    }

    _label->setPixmap(QPixmap::fromImage(*_image));
}
